package mornd.test6;

import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.core.MethodParameter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.web.context.request.ServletWebRequest;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.method.support.HandlerMethodReturnValueHandlerComposite;
import org.springframework.web.method.support.ModelAndViewContainer;
import org.springframework.web.servlet.View;
import org.springframework.web.servlet.mvc.method.annotation.*;
import org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator;
import org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver;

import java.lang.reflect.Method;
import java.nio.charset.StandardCharsets;
import java.util.Collection;
import java.util.Collections;
import java.util.Locale;

/**
 * @author: mornd
 * @dateTime: 2023/5/8 - 14:29
 * 返回值处理器解析
 */
@Slf4j
public class App {
    public static void main(String[] args) throws Exception {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(WebConfig.class);

        ServletWebRequest request = new ServletWebRequest(new MockHttpServletRequest(), new MockHttpServletResponse());
        ModelAndViewContainer container = new ModelAndViewContainer();
        HandlerMethodReturnValueHandlerComposite composite = getReturnValueHandler();
//        test1(context, composite, container, request);
        test7(context, composite, container, request);


    }

    // 解析 ModelAndView 类型返回值
    public static void test1(AnnotationConfigApplicationContext context,
                             HandlerMethodReturnValueHandlerComposite composite,
                             ModelAndViewContainer container,
                             ServletWebRequest request) throws Exception {
        Method test1 = Controller1.class.getMethod("test3");
        Controller1 controller1 = new Controller1();
        Object r = test1.invoke(controller1);
        HandlerMethod handlerMethod = new HandlerMethod(controller1, test1);
        MethodParameter returnType = handlerMethod.getReturnType();

        // 是否支持某种返回值类型
        if(composite.supportsReturnType(returnType)) {
            composite.handleReturnValue(r, returnType, container, request);
            System.out.println(container.getModel());
            System.out.println(container.getView());
            renderView(context, container, request);
        }
    }

    // 解析 @ResponseBody 注解
    public static void test7(AnnotationConfigApplicationContext context,
                             HandlerMethodReturnValueHandlerComposite composite,
                             ModelAndViewContainer container,
                             ServletWebRequest request) throws Exception {
        Method test1 = Controller1.class.getMethod("test7");
        Controller1 controller1 = new Controller1();
        Object r = test1.invoke(controller1);
        HandlerMethod handlerMethod = new HandlerMethod(controller1, test1);
        MethodParameter returnType = handlerMethod.getReturnType();

        // 是否支持某种返回值类型
        if(composite.supportsReturnType(returnType)) {
            composite.handleReturnValue(r, returnType, container, request);
            System.out.println(container.getModel());
            System.out.println(container.getView());
            System.out.println(container.isRequestHandled());
            MockHttpServletResponse response = (MockHttpServletResponse) request.getResponse();

            System.out.println("输出所有请求头信息");
            Collection<String> names = response.getHeaderNames();
            for (String name : names) {
                System.out.println(name + "=" +  response.getHeader(name));
            }

            // 输出响应体
            String body = new String(response.getContentAsByteArray(), "utf-8");
            System.out.println(body);
        }
    }

    /**
     * 工具方法，生成返回值组合处理器
     * @return
     */
    public static HandlerMethodReturnValueHandlerComposite getReturnValueHandler() {
        HandlerMethodReturnValueHandlerComposite composite = new HandlerMethodReturnValueHandlerComposite();
        // 处理 ModelAndView 返回值
        composite.addHandler(new ModelAndViewMethodReturnValueHandler());
        // 处理字符串类型返回值
        composite.addHandler(new ViewNameMethodReturnValueHandler());
        // 处理方法上标注了 @ModelAttribute 注解
        composite.addHandler(new ServletModelAttributeMethodProcessor(false));
        // HttpEntity 或 ResponseEntity
        composite.addHandler(new HttpEntityMethodProcessor(Collections.singletonList(new MappingJackson2HttpMessageConverter())));
        // HttpHeaders 类型
        composite.addHandler(new HttpHeadersReturnValueHandler());
        // @ResponseBody
        composite.addHandler(new RequestResponseBodyMethodProcessor(Collections.singletonList(new MappingJackson2HttpMessageConverter())));
        // // 处理方法上没有标注了 @ModelAttribute 注解
        composite.addHandler(new ServletModelAttributeMethodProcessor(true));
        return composite;
    }


    @SuppressWarnings("all")
    private static void renderView(AnnotationConfigApplicationContext context, ModelAndViewContainer container,
                                   ServletWebRequest webRequest) throws Exception {
        log.debug(">>>>>> 渲染视图");
        FreeMarkerViewResolver resolver = context.getBean(FreeMarkerViewResolver.class);
        String viewName = container.getViewName() != null ? container.getViewName() : new DefaultRequestToViewNameTranslator().getViewName(webRequest.getRequest());
        log.debug("没有获取到视图名, 采用默认视图名: {}", viewName);
        // 每次渲染时, 会产生新的视图对象, 它并非被 Spring 所管理, 但确实借助了 Spring 容器来执行初始化
        View view = resolver.resolveViewName(viewName, Locale.getDefault());
        view.render(container.getModel(), webRequest.getRequest(), webRequest.getResponse());
        System.out.println(new String(((MockHttpServletResponse) webRequest.getResponse()).getContentAsByteArray(), StandardCharsets.UTF_8));
    }
}
